﻿using System.ComponentModel;
using System.Reactive.Linq;
using System.Windows;
using Caliburn.Micro;
using PurchaseSales.Manage.Common.AOP;
using PurchaseSales.Manage.Common.Extensions;
using PurchaseSales.Manage.Model.Entities;
using PurchaseSales.Manage.Services;
using PurchaseSales.Manage.Views.UserControls;
using ReactiveUI;
using ReactiveUI.Xaml;
using System;

namespace PurchaseSales.Manage.ViewModels
{
    public class CommodityViewModel : Screen
    {
        private readonly ICommodityRepository _repository;
        private readonly IWindowManager _windowManager;
        public ReactiveAsyncCommand SelectedCustomerCommand { get; set; }
        public ReactiveAsyncCommand AddCommand { get; set; }
        public ReactiveAsyncCommand RemoveCommand { get; set; }
        public ReactiveAsyncCommand EditCommand { get; set; }
        public ReactiveAsyncCommand LoadCommand { get; set; }
        public ReactiveAsyncCommand SelectedCommodityCommand { get; set; }
        private ObservableAsPropertyHelper<ReactiveCollection<Commodity>> _commodities;
        private ObservableAsPropertyHelper<Commodity> _selectedCommodity;

        public CommodityViewModel(ICommodityRepository repository, IWindowManager windowManager)
        {
            _repository = repository;
            _windowManager = windowManager;

            LoadCommand = new ReactiveAsyncCommand();
            var commodities = LoadCommand.RegisterAsyncFunction(_ =>
                            {
                                var entities = _repository.GetAll();
                                return entities.ToObservable().CreateCollection();
                            });
            _commodities = new ObservableAsPropertyHelper<ReactiveCollection<Commodity>>(commodities, _ =>
                                {
                                    NotifyOfPropertyChange(() => Commodities);
                                });
            SelectedCommodityCommand = new ReactiveAsyncCommand();
            var @select = SelectedCommodityCommand.Select(o => o as Commodity);
            _selectedCommodity = new ObservableAsPropertyHelper<Commodity>(@select, a =>{});

            AddCommand = new ReactiveAsyncCommand();
            AddCommand.Subscribe(o =>
                                     {
                                         var commodity = DataBindingFactory.Create<Commodity>();
                                         var dialogViewModel = IoC.Get<IShowDialogViewModel<Commodity>>();
                                         dialogViewModel.ShowDialogContent = new AddCommodity();
                                         dialogViewModel.Entity = commodity;
                                         CanConfirm = dialogViewModel.CanConfirm;

                                         NotifyEntityChanged(commodity);

                                         var showDialog = _windowManager.ShowDialog(dialogViewModel);
                                         if (showDialog == true)
                                         {
                                             Commodities.Add(dialogViewModel.Entity);
                                             _repository.Save(dialogViewModel.Entity);
                                         }
                                     });

            RemoveCommand = new ReactiveAsyncCommand(_selectedCommodity.Select(x => x != null).StartWith(false));
            RemoveCommand.Subscribe(o =>
            {
                _repository.MakeTransient(SelectedCommodity);
                Commodities.Remove(SelectedCommodity);
                _repository.Commit();
            });
            RemoveCommand.ThrownExceptions.Subscribe(_ => MessageBox.Show("Remove Error"));

            EditCommand = new ReactiveAsyncCommand(_selectedCommodity.Select(x => x != null).ObserveOnDispatcher().StartWith(false));
            EditCommand.Subscribe(o =>
            {
                var dialogViewModel = IoC.Get<IShowDialogViewModel<Commodity>>();
                dialogViewModel.ShowDialogContent = new AddCommodity();
                dialogViewModel.Entity = SelectedCommodity;
                CanConfirm = dialogViewModel.CanConfirm;

                NotifyEntityChanged(SelectedCommodity);

                var showDialog = _windowManager.ShowDialog(dialogViewModel);
                if (showDialog == true)
                {
                    _repository.Save(dialogViewModel.Entity);
                }
                else
                {
                    _repository.Evict(dialogViewModel.Entity);
                    LoadCommand.Execute(this);
                }
            });

        }

        private void NotifyEntityChanged(Commodity commodity)
        {
            var entity = commodity as INotifyPropertyChanged;
            entity.SafeInvoke(x => x.PropertyChanged += (sender, args) => { CanConfirm.Invoke(CanSave(commodity)); });
        }

        public Action<bool> CanConfirm;

        public bool CanSave(Commodity commodity)
        {
            return !string.IsNullOrEmpty(commodity.Number) && !string.IsNullOrEmpty(commodity.Name);

        }

        public Commodity SelectedCommodity
        {
            get { return _selectedCommodity.Value; }
        }

        public ReactiveCollection<Commodity> Commodities
        {
            get { return _commodities.Value; }
        }
    }
}